`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/26 09:39:56
// Design Name: 
// Module Name: rv_ex
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`include "rv_config.v"
module rv_ex(
    input CLK,input RST,
    
    //Decode-->EX inst
    input [4:0] INST_TYPE,
    input [2:0] FUNC3,
    input [2:0] ALU_FUNC3,
    input INST30,
    input [4:0] RS1_INDEX,
    input [4:0] RS2_INDEX,
    input [4:0] RD_INDEX,
    
    //Decode-->EX Data
    input [31:0] RS1,
    input [31:0] RS2,
    input [31:0] IMM32,
    //PC chain-->EX
    input [31:0] PC,
    
    //Decode-->EX Cur thread_id
    input [1:0] THREAD_ID,
    //MEM-->EX forwarding
    input [1:0] MEM_THREAD_ID,
    input [4:0] MEM_RD_INDEX,
    
    //WB-->EX forwarding
    input [1:0] WB_THREAD_ID,
    input [4:0] WB_RD_INDEX,
    input [31:0] WB_RD_VALUE,

    //CSR -->EX
    input [31:0] CSR_DOUT,
    //Result of RS1 forwarding
    output [31:0] RS1_FORWARD,

    //EX-->MEM
    output [31:0] EX_RD_VALUE,

    //EX --> ALL MEMORY MODULES
    output [31:0] MEM_ADDR,
    output [31:0] MEM_DIN,
    
    //EX --> DMEM
    output DMEM_CS,
    
    //EX-->ISSUE
    output UPDATE_PC_VALID,
    output [31:0] UPDATE_PC
    );

    reg [31:0] src1,src2;
    wire [31:0] ex_rd_value;

    //Forwarding logic
    always @(*) begin
        if(RS1_INDEX==5'b0) src1=32'b0;
        else begin
            if((RS1_INDEX==MEM_RD_INDEX)&(THREAD_ID==MEM_THREAD_ID)) 
                src1=ex_rd_value;
            else begin 
                if((RS1_INDEX==WB_RD_INDEX)&(THREAD_ID==WB_THREAD_ID)) 
                    src1=WB_RD_VALUE;
                else src1=RS1;
                end
            end
        end
    assign RS1_FORWARD=src1;
    always @(*) begin
        if(RS2_INDEX==5'b0) src2=32'b0;
        else begin
            if((RS2_INDEX==MEM_RD_INDEX)&(THREAD_ID==MEM_THREAD_ID)) 
                src2=ex_rd_value;
            else begin
                if((RS2_INDEX==WB_RD_INDEX)&(THREAD_ID==WB_THREAD_ID)) 
                    src2=WB_RD_VALUE;
                else src2=RS2;
                end
            end
        end
    assign MEM_DIN=src2;


    //ALU
    reg [31:0] alu_src1,alu_src2;
    always @(*) begin
        case(INST_TYPE)
            `INST_LOAD,`INST_STORE,`INST_OP_IMM,`INST_LUI:begin  //rs1+imm32
                alu_src1=src1;alu_src2=IMM32;
                end
            `INST_OP,`INST_BRANCH: begin  //rs1+rs2
                alu_src1=src1;alu_src2=src2;
                end
            `INST_AUIPC,`INST_JALR,`INST_JAL:    begin  //PC+imm32
                alu_src1=PC;alu_src2=IMM32;
                end
            `INST_SYSTEM: begin//
                alu_src1=PC;alu_src2=IMM32;
                end
            default:begin
                alu_src1=src1;alu_src2=src2;
                end
        endcase
    end
    wire [31:0] alu_dout;
    wire eq;
    rvex_alu ALU (
      .src1 (alu_src1 ),
      .src2 (alu_src2 ),
      .func3 (ALU_FUNC3),
      .inst30 (INST30),
      .alu_out (alu_dout ),
      .eq  ( eq)
    );
    assign MEM_ADDR=alu_dout;
    wire [31:0] mem_addr;
    assign mem_addr=alu_dout;
    wire mem_inst_type;
    assign mem_inst_type=((INST_TYPE==`INST_LOAD)|(INST_TYPE==`INST_STORE))?1'b1:1'b0;
    assign DMEM_CS=(mem_inst_type&(mem_addr>=`DMEM_LOW_ADDR)&(mem_addr<`DMEM_HIGH_ADDR))?1'b1:1'b0;
    
    rvex_branch BRANCH_UNIT(
        .lt(alu_dout[0]),
        .eq(eq),
        .inst_type(INST_TYPE),
        .func3(FUNC3),
        .pc(PC),
        .rs1(src1),
        .imm32(IMM32),
        .update_pc_valid(UPDATE_PC_VALID),
        .update_pc(UPDATE_PC)
    );

    wire [31:0] ex_rd_din;
    assign ex_rd_din=(INST_TYPE==`INST_SYSTEM)?CSR_DOUT:alu_dout;
    regw #(.WIDTH(32)) EX_RD_VALUE_REG(CLK,RST,1'b1,ex_rd_din,ex_rd_value);
    assign EX_RD_VALUE=ex_rd_value;
endmodule